//
// Game Animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <animation/configuration.h>

#define DEFINE_GLUT_MAIN
#include <OpenTissue/utility/glut/glut_perspective_view_application.h>
#undef DEFINE_GLUT_MAIN


#include <OpenTissue/utility/gl/gl_util.h>
#include <OpenTissue/gpu/cg/cg_util.h>

#include <animation/game_animation_types.h>
#include <animation/terrain_shader.h>
#include <animation/grass_shader.h>
#include <animation/sky_shader.h>
#include <animation/shader/sun/sun_shader.h>
#include <animation/shader/moon/moon_shader.h>
#include <animation/shader/skydome/sky_dome_cloud_shader.h>
#include <animation/shader/water/water_shader.h>
#include <animation/shader/tree/tree_shader.h>
#include <animation/shader/flowers/flower_shader.h>
#include <animation/shader/grass/grass2_shader.h>
#include <animation/shader/3dtree/leafs/leafs_shader.h>
#include <animation/shader/3dtree/trunks/trunks_shader.h>

#include <animation/boid_shader.h>
#include <animation/cell_generator.h>
#include <animation/cloud_system.h>
#include <OpenTissue/core/containers/mesh/trimesh/trimesh.h>


#include <OpenTissue/core/containers/mesh/common/io/mesh_obj_read.h>
#include <OpenTissue/core/containers/mesh/common/util/mesh_compute_angle_weighted_vertex_normals.h>
#include <OpenTissue/core/containers/mesh/common/util/mesh_make_sphere.h>
#include <OpenTissue/core/containers/mesh/common/util/mesh_make_plane.h>


#include <animation/geometry/mesh2geometry.h>
#include <animation/compute_heightmap_point.h>

#include <iostream>
#include <sstream>

#include <OpenTissue/utility/utility_fps_counter.h> 

struct PlantStruct{
	bool visible;
	char* name;
	PlantStruct(bool avisible,char* aname){
		visible=avisible;
		name=aname;
	}
};
class Application 
  : public OpenTissue::glut::BasePerspectiveViewApplication< OpenTissue::math::BasicMathTypes<float,size_t> >
{
protected:

  typedef OpenTissue::glut::BasePerspectiveViewApplication< OpenTissue::math::BasicMathTypes<float,size_t> > base_class;
  typedef animation::GameAnimationTypes<math_types>   types;
  typedef types::geometry_type::coord_iterator coord_it;
  bool m_action[256];          ///< Boolean array used to keep track of the user actions/selections.

  typedef math_types::real_type                    real_type;
  typedef math_types::vector3_type                 vector3_type;
  typedef math_types::quaternion_type              quaternion_type;
  typedef math_types::matrix3x3_type               matrix3x3_type;

protected:

  bool m_wcs_visible;
  bool m_cam_visible;
  bool m_aabb_visible;
  bool m_depth_visible;
  bool m_terrain_visible;
  bool m_terrain_shader_on;
  bool m_terrain_wireframe;
  bool m_boid_visible;
  bool m_boid_mesh_on;
  bool m_sky_enabled;
  bool m_sky_shader_on;
  bool m_sky_wireframe;
  bool m_follow_boid;  ///< Makes camera follow boid around. Default is off.
  bool m_boid_per_pixel_lighting;
  bool m_reload_shaders;
  bool m_water_on;
  bool m_occlusion_on;

  int m_clouds_state;//0 nothing,1 skydome clouds,2 billboard 3 all;

  std::vector<PlantStruct> m_plants;//0:grass,1:tree,2:flowers,3:3d trees
protected:
  OpenTissue::utility::FPSCounter<real_type> fps; 
  animation::CellGenerator<types>    m_cell_generator;
  types::grid_manager                m_grid_manager;
  types::cell_sorting                m_cell_sorting;

  unsigned int m_I;            ///< Number of virtual grid cells along x-axis.
  unsigned int m_J;            ///< Number of virtual grid cells along y-axis.
  real_type    m_cell_width;   ///< Size of grid cell along x-axis.
  real_type    m_cell_height;  ///< Size of grid cell along y-axis.

  real_type    m_fog_density;
  real_type    m_fog_color[3];
protected:

  animation::GrassShader            m_grass_shader;  
  animation::Grass2Shader           m_grass_shader2;
  animation::FlowerShader           m_flower_shader;
  animation::TerrainShader          m_terrain_shader;
  animation::BoidShader             m_boid_shader;
  animation::TreeShader             m_tree_shader;
  animation::SkyShader               m_sky_shader;
  types::geometry_type               m_sky_dome;
  real_type                          m_dome_radius;

  types::geometry_type               m_tree_geometry[2];
  types::geometry_type               m_leaf_geometry[2];
  animation::LeafsShader             m_leaf_shader;
  animation::TrunksShader            m_trunk_shader;

  real_type                          m_time;

  vector3_type                       m_boid_position;
  vector3_type                       m_boid_normal;

  real_type                          m_boid_steering_angle;
  real_type                          m_boid_speed;
  vector3_type                       m_boid_dof;
  vector3_type                       m_boid_tracking_vector;


  types::geometry_type               m_boid_geometry;
  float                              m_water_level;//used to indicate at what height water is.

  


  vector3_type                       m_sun_dir_wcs;
  vector3_type                       m_moon_dir_wcs;
  vector3_type                       m_moon2_dir_wcs;
 // vector3_type                       m_moon_dir_view;
 // vector3_type                       m_sun_dir_view;
  vector3_type                       m_light_dir_view;
  float                              m_light_intensity;

  Cloud_System< math_types >         m_clouds;

  animation::SunShader             m_sun_shader;
  animation::MoonShader            m_moon_shader;
  animation::SkyDomeCloudShader    m_sky_cloud_shader;

  animation::WaterShader           m_water_shader;
  int m_last_count;

  float                              m_time_step;
  float                              m_day_length;
  float                              m_day_time;
  float								 m_rotation_angle;
  float								 m_deg2rad;
public:

	Application():m_clouds(150,150){
    //--- This is how one could change the default size of the main window
    this->width() = 512;
    this->height() = 512;
	m_deg2rad=0.0174532925;
	m_sun_dir_wcs=vector3_type(0,0,-1);
	m_moon_dir_wcs=m_moon2_dir_wcs=rotateY(vector3_type(0,0,1),10.0*m_deg2rad);
	m_time_step=0.1;
	m_day_length=20.0;	
	m_rotation_angle=(360.0/(m_day_length/m_time_step))*m_deg2rad;
	m_day_time=0;
	m_last_count=this->camera().getCounter();
    m_boid_speed=0;
	m_fog_color[0]=0.7;
	m_fog_color[1]=0.7;
	m_fog_color[2]=0.7;
  m_water_level=-0.4;
	m_fog_density=0;
  }
public:

  char const * do_get_title() const { return "The Swamp Thing"; }
  float FogDensity(){
	  return m_fog_density;
	  //return log10(m_fog_density)/log10(2.0);
  }
  void do_display()
  {
    render_frames( m_wcs_visible, m_cam_visible );
	pre_render_water(m_water_on);	


	if(this->camera().getCounter()!=m_last_count){
		//--- depth sorting of cells
		m_cell_sorting.sort(this->camera());
		//--- CPU side culling of cells, first cheaper test then more expensive tests
		this->frustum().update();	
		types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
		types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();

		m_last_count=this->camera().getCounter();
		int i=0;
		for(;cell!=cell_end;++cell){		  
			if(cell->depth()<0) {	
				cell->visible() = false;
				continue;
			}
			if(!this->frustum().contains(cell->get_aabb())){
				cell->visible() = false;
				continue;
			}
			cell->visible() = true;	
			i++;
			cell->m_occlude_testet=false;
		}	 
	}
	glPushMatrix();
	//glScalef(1,1,-1);
    render_aabb( m_aabb_visible,m_depth_visible);
	render_sky_dome(m_sky_enabled,m_sky_shader_on,m_sky_wireframe,false);

    render_terrain(m_terrain_visible, m_terrain_shader_on,m_terrain_wireframe,m_occlusion_on);

    render_boid(m_boid_visible, m_boid_mesh_on, m_boid_per_pixel_lighting);
    
	render_clouds(m_clouds_state);
	render_grass(m_plants[0].visible);
	render_grass2(m_plants[4].visible);
	render_tree(m_plants[1].visible,m_plants[3].visible);
	render_water(m_water_on);
	render_flower(m_plants[2].visible);
	glPopMatrix();
	
	
	m_reload_shaders=false;
	if (fps.frame()){
		std::cout << "FPS = " << fps() << std::endl;
	}
  }

  void do_action(unsigned char choice)
  {

    real_type const angle = math_types::value_traits::degree()*5.0;
    // Toggle state
    m_action[choice] = ! m_action[choice];
    switch ( choice )
    {
    case 'a': m_boid_steering_angle+=angle;   break;
    case 'd': m_boid_steering_angle-=angle;  
	break;
    case 'w': 
		m_boid_speed+=0.1;     
		std::cout<<"Boid Speed:"<<m_boid_speed<<std::endl;
	break;
    case 's': 		
		m_boid_speed-=0.1;  
		std::cout<<"Boid Speed:"<<m_boid_speed<<std::endl;
	break;
	case '-':this->camera().move(1);break;
    case '+':this->camera().move(-1);break;

    case 'f':
      m_follow_boid = !m_follow_boid;
      std::cout << "follow boid  = " << m_follow_boid << std::endl;
      break;
    case '!':
      m_wcs_visible = !m_wcs_visible;
      std::cout << "wcs frame = " << m_wcs_visible << std::endl;
      break;
    case '\"':
      m_cam_visible = !m_cam_visible;
      std::cout << "camera frame = " << m_cam_visible << std::endl;
      break;
    case '#':
      m_aabb_visible = !m_aabb_visible;
      std::cout << "aabb visible = " << m_aabb_visible << std::endl;
      break;
    case '%':
      m_depth_visible = !m_depth_visible;
      std::cout << "depth info = " << m_depth_visible << std::endl;
      break;
    case '0':
      m_boid_per_pixel_lighting = !m_boid_per_pixel_lighting;
      std::cout << "boid per pixel lighting = " << m_boid_per_pixel_lighting << std::endl;
      break;
    case '1':
      m_terrain_visible = !m_terrain_visible;
      std::cout << "terrain visible = " << m_terrain_visible << std::endl;
      break;
    case '2':
      m_terrain_shader_on = !m_terrain_shader_on;
      std::cout << "Terrain shader = " << m_terrain_shader_on << std::endl;
      break;
    case '3':
      m_terrain_wireframe = !m_terrain_wireframe;
      std::cout << "Terrain wireframe = " << m_terrain_wireframe << std::endl;
      break;
    case '4':
      m_sky_enabled = !m_sky_enabled;
      std::cout << "sky enabled = " << m_sky_enabled << std::endl;
      break;
    case '5':
      m_sky_shader_on = !m_sky_shader_on;
      std::cout << "sky shader = " << m_sky_shader_on << std::endl;
      break;
    case '6':
      m_sky_wireframe = !m_sky_wireframe;
      std::cout << "sky wireframe = " << m_sky_wireframe << std::endl;
      break;
    case '7':
		for(unsigned int i=0;i<m_plants.size();i++){
			if(m_plants[i].visible){
				m_plants[i].visible=false;
				std::cout <<m_plants[i].name<<" off"<< std::endl;
			}else{
				m_plants[i].visible=true;
				std::cout <<m_plants[i].name<<" on"<< std::endl;
				break;
			}
		}
    break;
    case '8':
      m_boid_visible = !m_boid_visible;
      std::cout << "boid visible = " << m_boid_visible << std::endl;
      break;
    case '9':
      m_boid_mesh_on = !m_boid_mesh_on;
      std::cout << "boid mesh = " << m_boid_mesh_on << std::endl;
    break;
    case 'r':
      m_reload_shaders =true;
      std::cout << "Reload active shaders" << std::endl;
    break;
    case 'x':
		m_water_on =!m_water_on;
		std::cout << "Water "<<m_water_on<< std::endl;
    break;
    case 'c':
		m_clouds_state++;
		if(m_clouds_state==4)m_clouds_state=0;
		std::cout << "Clouds "<<m_clouds_state<< std::endl;
    break;
    case 'v':
		m_occlusion_on =!m_occlusion_on;
		std::cout << "Occlusion on "<<m_occlusion_on<< std::endl;
    break;
    case 'n':
		//Speeds up the application by enlarging the time step
		m_time_step*=2.0;
		m_rotation_angle=(360.0/(m_day_length/m_time_step))*m_deg2rad;
		std::cout << "Speed "<<m_time_step<< std::endl;
    break;
	case 'm':
		//Speeds down the application by decreasing the time step
		m_time_step/=2.0;
		m_rotation_angle=(360.0/(m_day_length/m_time_step))*m_deg2rad;
		std::cout << "Speed "<<m_time_step<< std::endl;
    break;
	case 'i':
		std::cout<<"Current Settings"<<std::endl
			     <<(m_follow_boid?"Following Boid":"Not following Boid")<<std::endl
			     <<"Terrain Shader "<<(m_terrain_shader_on?"On":"Off")<<std::endl
			     <<"Boid Mesh "<<(m_boid_mesh_on?"On":"Off")<<std::endl
			     <<(m_boid_per_pixel_lighting?"Boid Pixel Ligthed":"Boid Vertex Ligthed")<<std::endl
			     <<"Sky "<<(m_sky_enabled?"enabled":"disabled")<<std::endl
			     <<"Sky Shader "<<(m_sky_shader_on?"On":"Off")<<std::endl;
		
		for(unsigned int i=0;i<m_plants.size();i++){
			std::cout <<m_plants[i].name;
			if(m_plants[i].visible){
				std::cout<<" on"<< std::endl;
			}else{
				std::cout<<" off"<< std::endl;
			}
		}		
		std::cout<<"End Current Settings"<<std::endl;

    break;
	case 'h':
		m_fog_density=(m_fog_density-0.005>0.0)?m_fog_density-0.005:0;
		std::cout<<"Density:"<<m_fog_density<<std::endl;
	break;
	case 'H':
		m_fog_density+=0.005;	
		std::cout<<"Density:"<<m_fog_density<<std::endl;
	break;
	case 'b':
		m_water_level+=0.05;	
		std::cout<<"Water Level:"<<m_water_level<<std::endl;
	break;
	case 'B':
		m_water_level-=0.05;	
		std::cout<<"Water Level:"<<m_water_level<<std::endl;
	break;
    default:    std::cout << "You pressed " << choice << std::endl;    break;
    };
  }

  void do_init_right_click_menu(int main_menu, void menu(int entry))
  {
    int controls = glutCreateMenu( menu );
    glutAddMenuEntry( "[a] move avatar left", 'a' );
    glutAddMenuEntry( "[s] move avatar right", 's' );
    glutAddMenuEntry( "[w] move accelerate avatar", 'w' );
    glutAddMenuEntry( "[z] move decelerate avatar", 'z' );

    glutAddMenuEntry( "[f] toggle follow boid", 'f' );
    glutAddMenuEntry( "[!] toggle wcs frame", '!' );
    glutAddMenuEntry( "[\"] toggle camera frame", '\"' );
    glutAddMenuEntry( "[#] toggle aabb", '#' );
    glutAddMenuEntry( "[%] toggle depth info", '%' );
    glutAddMenuEntry( "[1] toggle terrain visible", '1' );
    glutAddMenuEntry( "[2] toggle terrain shader", '2' );
    glutAddMenuEntry( "[3] toggle terrain wireframe", '3' );
    glutAddMenuEntry( "[4] toggle sky enabled", '4' );
    glutAddMenuEntry( "[5] toggle sky shader", '5' );
    glutAddMenuEntry( "[6] toggle sky wireframe", '6' );
    glutAddMenuEntry( "[7] toggle plants", '7' );
    glutAddMenuEntry( "[8] toggle boid visible", '8' );
    glutAddMenuEntry( "[9] toggle boid mesh", '9' );
    glutAddMenuEntry( "[0] toggle boid per pixel lighting ", '0' );
    glutAddMenuEntry( "[c] toggle cloud type", 'c' );
    glutAddMenuEntry( "[x] toggle water visible", 'x' );
    glutAddMenuEntry( "[h] toggle decrement fog density", 'h' );
    glutAddMenuEntry( "[H] toggle increment fog density", 'H' );
    glutAddMenuEntry( "[b] toggle raise water level    ", 'b' );
    glutAddMenuEntry( "[B] toggle lower water level    ", 'B' );
    glutAddMenuEntry( "[m] toggle decelerate time      ", 'm' );
    glutAddMenuEntry( "[n] toggle accelerate time      ", 'n' );
    glutSetMenu( main_menu );
    glutAddSubMenu( "Controls", controls );
  }

  void do_init()
  {
    OpenTissue::cg::startup();

    math_types::vector3_type position( 0, -1, 1);
    math_types::vector3_type target(0,0,0);
    math_types::vector3_type up(0,0,1);

    this->camera().init(position, target, up);


    //--- Create a virtual grid
    m_I           = 9;
    m_J           = 9;
    m_cell_width  = 15.0;
    m_cell_height = 15.0;
    m_grid_manager.init(m_I,m_J,m_cell_width,m_cell_height,m_cell_generator);

    //--- Place boid in virtual grid
    m_boid_position = vector3_type(0,0,0);
    m_boid_steering_angle = 0.0;
	m_boid_speed=0.0;
    m_boid_dof =  vector3_type(0.0,1.0,0.0);
    m_boid_normal =  vector3_type(0.0,0.0,1.0);
    m_boid_tracking_vector = vector3_type(0.75,-2.0,0.75)*3;


    //--- Prepare virtual grid for visualization
    m_cell_sorting.init(m_grid_manager);

    //--- setup sky dome geometry
    OpenTissue::trimesh::TriMesh<> sphere;
	real_type dx =70.0; //m_I*m_cell_width;
    real_type dy =70.0;// m_J*m_cell_height;
    m_dome_radius = 1.5*std::min(dx,dy)*.5;
    OpenTissue::mesh::make_sphere(m_dome_radius,32,32,sphere);
    mesh2geometry(sphere,m_sky_dome);



	  
	  //--- tree stuff
	OpenTissue::trimesh::TriMesh<> temp_mesh;
	OpenTissue::mesh::obj_read(demo_path + "TheSwampThing2008/data/tree2.obj",temp_mesh);
	OpenTissue::mesh::compute_angle_weighted_vertex_normals(temp_mesh);
	mesh2geometry(temp_mesh,m_tree_geometry[0]);
	m_tree_geometry[0].cleanup_vertex_object();
	

	OpenTissue::mesh::obj_read(demo_path + "TheSwampThing2008/data/leaf2.obj",temp_mesh);
	OpenTissue::mesh::compute_angle_weighted_vertex_normals(temp_mesh);
	mesh2geometry(temp_mesh,m_leaf_geometry[0]);
	m_leaf_geometry[0].cleanup_vertex_object();



	OpenTissue::mesh::obj_read(demo_path + "TheSwampThing2008/data/tree.obj",temp_mesh);
	OpenTissue::mesh::compute_angle_weighted_vertex_normals(temp_mesh);
	mesh2geometry(temp_mesh,m_tree_geometry[1]);
	m_tree_geometry[1].cleanup_vertex_object();
	

	OpenTissue::mesh::obj_read(demo_path + "TheSwampThing2008/data/leaf.obj",temp_mesh);
	OpenTissue::mesh::compute_angle_weighted_vertex_normals(temp_mesh);
	mesh2geometry(temp_mesh,m_leaf_geometry[1]);
	m_leaf_geometry[1].cleanup_vertex_object();



    //--- setup boid geometry
    OpenTissue::trimesh::TriMesh<> boid_mesh;
    OpenTissue::mesh::obj_read(demo_path + "TheSwampThing2008/data/boid.obj",boid_mesh);
    OpenTissue::mesh::compute_angle_weighted_vertex_normals(boid_mesh);
    mesh2geometry(boid_mesh,m_boid_geometry);



    //--- setup UI and time
    m_time                    = 0.0f;
    m_follow_boid             = false;
    m_wcs_visible             = false;
    m_cam_visible             = false;
    m_aabb_visible            = false;
    m_depth_visible           = false;
    m_terrain_visible         = true;
    m_terrain_shader_on       = false;
    m_terrain_wireframe       = false;
    m_boid_visible            = false;
    m_boid_mesh_on            = true;
    m_sky_enabled             = false;
    m_sky_shader_on           = true;
    m_sky_wireframe           = false;
    m_boid_per_pixel_lighting = false;
    m_reload_shaders          = false;
	m_clouds_state            = false;
	m_water_on                =false;
	m_occlusion_on            =false;



	m_plants.push_back(PlantStruct(false,"Grass"));
	m_plants.push_back(PlantStruct(false,"Trees"));
	m_plants.push_back(PlantStruct(false,"Flowers"));
	m_plants.push_back(PlantStruct(false,"3D Trees"));
	m_plants.push_back(PlantStruct(false,"Grass 2"));
  }

  vector3_type rotateZ(vector3_type input,float angle){
	  vector3_type temp;
	  temp(2)=input(2);
	  temp(1)= input(0)*sin(angle) + input(1)*cos(angle);
	  temp(0)= input(0)*cos(angle) - input(1)*sin(angle);
	  return temp;
  }
  vector3_type rotateY(vector3_type input,float angle){
	  vector3_type temp;
	  temp(1)=input(1);
	  temp(2)= input(2)*cos(angle) - input(0)*sin(angle);
	  temp(0)= input(2)*sin(angle) + input(0)*cos(angle);
	  return temp;
  }

  //Takes the world lights and sets the view counter parts
  void 	LightsToView(){
	const GLfloat* wcs_view=m_camera.get_modelview_matrix();
/*
	0 4 8 12        a         x=0*a+4*b+8*c+12
    1 5 9 13        b         y=1*a+5*b+9*c+13 
	2 6 10 14       c         z=2*a+6*b+10*c+14 
	3 7 11 15       d
	*/

	if(m_sun_dir_wcs(2)>=m_moon2_dir_wcs(2)){
		m_light_intensity=1.2;
		m_light_dir_view=unit(vector3_type(
		wcs_view[0]*m_sun_dir_wcs(0)+wcs_view[4]*m_sun_dir_wcs(1)+wcs_view[8]*m_sun_dir_wcs(2),
		wcs_view[1]*m_sun_dir_wcs(0)+wcs_view[5]*m_sun_dir_wcs(1)+wcs_view[9]*m_sun_dir_wcs(2),
		wcs_view[2]*m_sun_dir_wcs(0)+wcs_view[6]*m_sun_dir_wcs(1)+wcs_view[10]*m_sun_dir_wcs(2)));
	}else{
		m_light_intensity=0.4;
		m_light_dir_view=unit(vector3_type(
		wcs_view[0]*m_moon_dir_wcs(0)+wcs_view[4]*m_moon_dir_wcs(1)+wcs_view[8]*m_moon_dir_wcs(2),
		wcs_view[1]*m_moon_dir_wcs(0)+wcs_view[5]*m_moon_dir_wcs(1)+wcs_view[9]*m_moon_dir_wcs(2),
		wcs_view[2]*m_moon_dir_wcs(0)+wcs_view[5]*m_moon_dir_wcs(1)+wcs_view[10]*m_moon_dir_wcs(2)));
	}
  }
  void do_run()
  {
    m_time += m_time_step;
	m_sun_dir_wcs=rotateY(m_sun_dir_wcs,m_rotation_angle);
	m_moon2_dir_wcs=rotateY(m_moon2_dir_wcs,m_rotation_angle);
	m_moon_dir_wcs=rotateZ(m_moon2_dir_wcs,5*m_deg2rad);
	LightsToView();
    movement_update();
	m_day_time+=m_time_step;
	if(m_day_time>m_day_length){
		m_day_time-=m_day_length;
	}

  }

  void do_shutdown()
  {
    OpenTissue::cg::shutdown();
  }


  void mouse_up(double cur_x,double cur_y,bool shift,bool ctrl,bool alt,bool left,bool middle,bool right) 
  {
    base_class::mouse_up(cur_x,cur_y,shift,ctrl,alt,left,middle,right) ;
    update_boid_tracking_vector();
  }

  void mouse_move(double cur_x,double cur_y)
  {
    base_class::mouse_move(cur_x,cur_y);
    update_boid_tracking_vector();
  }




public:

  void render_frames(bool wcs,bool camera)
  {
    if(wcs)
      OpenTissue::gl::DrawFrame(vector3_type(),quaternion_type());
    if(camera)
    {
      OpenTissue::gl::ColorPicker(0.1,.1,.1);
      OpenTissue::gl::DrawVector(vector3_type(),m_camera.target());
      OpenTissue::gl::ColorPicker(0,.5,.5);
      OpenTissue::gl::DrawVector(m_camera.target(),m_camera.right());
      OpenTissue::gl::DrawVector(m_camera.target(),m_camera.up());
      OpenTissue::gl::DrawVector(m_camera.target(),m_camera.dof());
    }
  }

  void render_aabb( bool enabled, bool depth_info)
  {
    if(!enabled)
      return;
    types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
    types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();
    for(;cell!=cell_end;++cell)
    {
      OpenTissue::gl::ColorPicker(
		  (GLfloat)(rand()%255)/255.0, 
		  (GLfloat) (rand()%255)/255.0, 
		  (GLfloat) (rand()%255)/255.0);
      OpenTissue::gl::DrawAABB( cell->get_aabb(), GL_LINE_LOOP);
      if(depth_info)
      {
        OpenTissue::gl::ColorPicker(1,0,0);
        std::stringstream text;
        text << cell->depth();
        OpenTissue::gl::DrawString(text.str(),cell->get_center()+ vector3_type(0,0,2), m_grid_manager.dx() );
      }
    }
  }

 

  void render_terrain( bool enabled, bool shader, bool wireframe,bool occlusion){
	  if(!enabled){
		  return;
	  }

	  types::cell_sorting::cell_reverse_iterator cell      = m_cell_sorting.rbegin();
	  types::cell_sorting::cell_reverse_iterator cell_end  = m_cell_sorting.rend();	  

	  if(shader){
		  m_terrain_shader.pre_render(m_reload_shaders,
			  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
			  m_light_intensity,
			  FogDensity(),
			  m_fog_color[0],m_fog_color[1],m_fog_color[2]);
		  /*
		  m_terrain_shader.pre_render(m_reload_shaders,
			  m_sun_dir_view(0),m_sun_dir_view(1),m_sun_dir_view(2),
			  m_moon_dir_view(0),m_moon_dir_view(1),m_moon_dir_view(2),
			  FogDensity(),
			  m_fog_color[0],m_fog_color[1],m_fog_color[2]);
			  */
	  }else{
		  OpenTissue::gl::ColorPicker(0.7,0.5,.1);
	  }

	  
	  if(wireframe){
		  for(;cell!=cell_end;++cell){
			  if(cell->visible()){
				  cell->get_geometry(0).brute_opengl_render(GL_LINE_LOOP);
			  }
		  }
	  }else{
		  if(occlusion){
			  int i=0;
			  int draws=0;
			  m_terrain_shader.enable();
			  for(;cell!=cell_end;++cell){ 
				  if(cell->visible()){
					  if(cell->m_occlude_testet==false){
						  m_terrain_shader.disable();
						  cell->m_occlude_testet=true;
						  GLuint queries[1];
						  glGenQueriesARB(1,queries);
						  glDepthMask(GL_FALSE); 
						  glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
						  glBeginQueryARB( GL_SAMPLES_PASSED_ARB,queries[0]);
						  OpenTissue::gl::DrawAABB( cell->get_aabb(), false);
						  glEndQueryARB(GL_SAMPLES_PASSED_ARB);
						  glDepthMask(GL_TRUE); 
						  glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
						  GLuint pixelCount;
						  glGetQueryObjectuivARB(queries[0], GL_QUERY_RESULT, &pixelCount);
						  glDeleteQueriesARB(1,queries);
						  m_terrain_shader.enable();
						  if(pixelCount==0){
							  i++;
							  cell->visible()=false;
							  continue;
						  }
						  
					  }
					  cell->get_geometry(0).vertex_object_render();
					  draws++;				  
				  }
			  }
			  m_terrain_shader.disable();
			  if(i>0){
				  std::cout<<"Cells occluded:"<<i<<std::endl;
				  std::cout<<"Cells drawn:"<<draws<<std::endl;
			  }
		  }else{
			  if(shader)m_terrain_shader.enable();
			  for(;cell!=cell_end;++cell){ 
				  if(cell->visible()){
					  cell->get_geometry(0).vertex_object_render();
				  }
			  }
			  if(shader)m_terrain_shader.disable();

		  }
	  }
  }

  float exp_curve(float t,float from,float to,float a){
		  return pow((t-from)/(to-from),a);
	  }
  void render_grass2( bool enabled){
	  if(!enabled){
		  return;
	  }
      float h=0;//length
	  float m=0.10;//max length
	  float s=m/50.0;//step size
	  float a=0.01;//min alpha value
	  float as=1./50.0;//alpha step size
	  for(int i=0;i<50;i++){
		  types::cell_sorting::cell_reverse_iterator cell      = m_cell_sorting.rbegin();
		  types::cell_sorting::cell_reverse_iterator cell_end  = m_cell_sorting.rend();	
		  float wx=sin(m_time)*0.2*exp_curve(h,0.0,m,2);
		  float wy=0;
		  h+=s;
		  a+=as;
		  
		  m_grass_shader2.pre_render(m_reload_shaders,
			  
			  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
			  m_light_intensity,
			  FogDensity(),
			  m_fog_color[0],m_fog_color[1],m_fog_color[2],a,h,wx,wy);
		    m_grass_shader2.enable();
		  for(;cell!=cell_end;++cell){ 
			  if(cell->visible()){
				  cell->get_geometry(0).vertex_object_render();
			  }
		  }
		  m_grass_shader2.disable();
	  }
  }
  void render_tree(bool d2,bool d3){
	  if(!d2&&!d3)
		  return;
        
	  if(d3){
		  types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
		  types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();		 
		  for(;cell!=cell_end;++cell){
			  if(cell->visible()){
				  for(types::geometry_type::vertex_iterator v=cell->get_geometry(5).m_vertices.begin();
					  v!=cell->get_geometry(5).m_vertices.end();
					  ++v){
						  glPushMatrix();  
						  glTranslatef(v->m_coord(0),v->m_coord(1),v->m_coord(2));
						 // m_leaf_texture->bind();
						  m_leaf_shader.pre_render(
							  m_reload_shaders,
							  m_time,
							  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
							  m_light_intensity
							  );

						  m_leaf_geometry[(int)v->m_tex0[0]].vertex_object_render();
						  m_leaf_shader.post_render();
						  if(!m_trunk_shader.pre_render(
							  m_reload_shaders,
							  m_time,
							  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
							  m_light_intensity
							  )){
								  break;
						  }
						  m_tree_geometry[(int)v->m_tex0[0]].vertex_object_render();
						  m_trunk_shader.post_render();
						  glPopMatrix();
				  }
			  }
		  }
	  }
	  if(d2){

	
	      types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
    types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();

	  m_tree_shader.pre_render(
		  m_reload_shaders,
		  m_camera.right()(0), m_camera.right()(1), m_camera.right()(2),
		  m_camera.up()(0)   , m_camera.up()(1)   , m_camera.up()(2),
		  m_time,
		  70.0f,  //--- visibility range of grass clumps, used to be 50
		  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
		  m_light_intensity,
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2]);

    //--- back to front render order
    for(;cell!=cell_end;++cell){
		if(cell->visible()){
			cell->get_geometry(2).vertex_object_render();
		}
    }
	m_tree_shader.post_render();}
  }
  void render_flower( bool enabled){
	  if(!enabled)
		  return;

	  m_flower_shader.pre_render(
		  m_reload_shaders,
		  m_camera.right()(0), m_camera.right()(1), m_camera.right()(2),
		  m_camera.up()(0)   , m_camera.up()(1)   , m_camera.up()(2),
		  m_time,
		  100.0f,  //--- visibility range of grass clumps, used to be 50
		  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
		  m_light_intensity,
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2]);

    //--- back to front render order
    types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
    types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();
    for(;cell!=cell_end;++cell){
		if(cell->visible()){
			cell->get_geometry(3).vertex_object_render();
		}
    }
    m_flower_shader.post_render();
  }


  void render_grass( bool enabled){
	  if(!enabled)
		  return;
	  m_grass_shader.pre_render(
		  m_reload_shaders,
		  m_camera.right()(0), m_camera.right()(1), m_camera.right()(2),
		  m_camera.up()(0)   , m_camera.up()(1)   , m_camera.up()(2),
		  m_time,
		  100.0f,  //--- visibility range of grass clumps, used to be 50
		  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
		  m_light_intensity,
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2]);

    //--- back to front render order
    types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
    types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();
    for(;cell!=cell_end;++cell){
		if(cell->visible()){
			cell->get_geometry(1).vertex_object_render();
		}
    }
    m_grass_shader.post_render();
  }
  void screenToTexture(OpenTissue::texture::texture2D_pointer texture,bool file=false,char* name=""){

	  texture->bind();
	  glCopyTexImage2D(
		  GL_TEXTURE_2D,
		  0, 
		  GL_RGBA,
		  0, 
		  0,
		  texture->width(),
		  texture->height(),
		  0);
	  glBindTexture(GL_TEXTURE_2D, 0);
	  glDisable(GL_TEXTURE_2D);
	  if(file){
	    OpenTissue::image::write(name , *OpenTissue::image::screen_capture() );
	  }

  }
  void pre_render_water(bool on){
	  if(!on)return;    
	  /*create the textures*/
	  m_water_shader.create_textures();
      

	  vector3_type position = m_camera.position();
      vector3_type target   = m_camera.target();
	  vector3_type up       = m_camera.up();
	  //START creates the reflection texture
	  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	  glViewport( 0, 0, m_water_shader.m_reflect_texture->width(), m_water_shader.m_reflect_texture->height() );
	  glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
	  OpenTissue::gl::LoadCameraMatrix(m_camera);
	  m_frustum.update();	    
	  double waterClip[4]={0,0,-1,m_water_level};
	  glPushMatrix();
	  glClipPlane(GL_CLIP_PLANE0, waterClip);
	  glEnable(GL_CLIP_PLANE0);
	  glTranslatef(0,0,m_water_level*2.0f);
	  glScalef(1,1,-1);
	  m_light_dir_view=-m_light_dir_view;//flip the direction of the ligth cause the scene is flipped
	  render_sky_dome ( m_sky_enabled , m_sky_shader_on , m_sky_wireframe,true);	
	  glCullFace(GL_FRONT);
	  glEnable(GL_NORMALIZE);
	  
	  render_boid(m_boid_visible,m_boid_mesh_on,m_boid_per_pixel_lighting);
	  render_terrain(m_terrain_visible,m_terrain_shader_on,m_terrain_wireframe,false);
	  render_tree(m_plants[1].visible,m_plants[3].visible);	 
	  render_grass(m_plants[0].visible);
	  render_flower(m_plants[2].visible);
	  screenToTexture(m_water_shader.m_reflect_texture,false,"reflection.png");
	  glDisable(GL_CLIP_PLANE0);
	  glCullFace(GL_BACK);
	  glDisable(GL_NORMALIZE);
	  glPopMatrix();
	  //END creates the reflection texture

	  //Start create Bottom
      /*
	  m_camera.init(position,target,up);
	  
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  	  glViewport( 0, 0, m_water_shader.m_bottom_texture->width(), m_water_shader.m_bottom_texture->height() );  
	  waterClip[2]=-1.0;waterClip[3]=0;
	  glClipPlane(GL_CLIP_PLANE0, waterClip);
	  glEnable(GL_CLIP_PLANE0);
	  glMatrixMode( GL_MODELVIEW );
      OpenTissue::gl::LoadCameraMatrix(m_camera);
      m_frustum.update();
	  render_terrain(m_terrain_visible,m_terrain_shader_on,m_terrain_wireframe,false);
	  screenToTexture(m_water_shader.m_bottom_texture,false,"bottom.png");
	  glDisable(GL_CLIP_PLANE0);
	  */
	  m_camera.init(position,target,up);
	  LightsToView();
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
      glMatrixMode( GL_MODELVIEW );
      OpenTissue::gl::LoadCameraMatrix(m_camera);
      m_frustum.update();
	  glViewport( 0, 0,this->width(), this->height() );
	  m_last_count+=3;
  }

  void render_water(bool on){
	  if(!on)return;
	  

	  m_water_shader.pre_render(
		  m_reload_shaders,
		  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
		  m_light_intensity,
      m_water_level,
      //m_sun_dir_wcs(0)   , m_sun_dir_wcs(1)   , m_sun_dir_wcs(2),
	 // m_moon_dir_wcs(0)   , m_moon_dir_wcs(1)   , m_moon_dir_wcs(2),
	  m_camera.position()(0)   , m_camera.position()(1)   , m_camera.position()(2),
      m_time);


	  OpenTissue::gl::ColorPicker(0,0,1);
/*
	  types::cell_type * cell = &(m_grid_manager.cell(m_grid_manager.s(),m_grid_manager.t()));
	  glPushMatrix();
	  real_type x=cell->get_center()(0);
	  real_type y=cell->get_center()(1);
	  OpenTissue::gl::Transform(vector3_type(x,y,-0.4));

	  for(types::geometry_type::vertex_iterator v=m_water_plane.m_vertices.begin();v!=m_water_plane.m_vertices.end();++v){
		types::cell_type * cell=&(m_grid_manager.cell(m_grid_manager.get_s(m_grid_manager.get_i(v->m_coord(0)+x)),m_grid_manager.get_t(m_grid_manager.get_j(v->m_coord(1)+y))));
		vector3_type position;
		vector3_type normal;
		compute_heightmap_point(
			cell->get_geometry(0)
			, m_cell_generator.I()
			, m_cell_generator.J()
			, m_cell_width
			, m_cell_height
			, v->m_coord(0)+x
			, v->m_coord(1)+y
			, position
			, normal);
		v->m_coord(2)=position(2);
	  }
	  */
	  /*
	  m_water_shader.setMatrix();
	  m_water_shader.enable();
	  m_water_plane.vertex_object_render();
	  m_water_shader.disable();
	  glPopMatrix();*/
	  m_water_shader.setMatrix();
	  m_water_shader.enable();
	  types::cell_sorting::cell_iterator cell      = m_cell_sorting.begin();
	  types::cell_sorting::cell_iterator cell_end  = m_cell_sorting.end();
	  for(;cell!=cell_end;++cell){
		  if(cell->visible()&&cell->get_aabb().min()(2)<m_water_level){
			  cell->get_geometry(4).vertex_object_render();
			  
		  }  
	  } 
	  m_water_shader.post_render();
  }
  void render_boid(bool enabled,bool use_mesh, bool per_pixel_lighting)
  {
    if(!enabled)
      return;

     

    if(use_mesh){
		m_boid_shader.create(
			m_reload_shaders, 
			per_pixel_lighting);
      glPushMatrix();
      vector3_type xaxis = m_boid_dof % m_boid_normal;
      vector3_type yaxis = m_boid_normal;
      vector3_type zaxis = -m_boid_dof;
      matrix3x3_type R(
        xaxis(0),yaxis(0),zaxis(0)
        ,xaxis(1),yaxis(1),zaxis(1)
        ,xaxis(2),yaxis(2),zaxis(2)
        );

	  
      OpenTissue::gl::Transform(m_boid_normal); //--- make it hover a little
      OpenTissue::gl::Transform(m_boid_position);
      quaternion_type Q;
      Q = R;	
      OpenTissue::gl::Transform(Q);
      OpenTissue::gl::ColorPicker(.75,0.2,0.1);
      m_boid_shader.pre_render(
		  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
		  m_light_intensity,
		  m_camera.position()(0),m_camera.position()(1),m_camera.position()(2),
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2]
	  );
      m_boid_geometry.vertex_object_render();
      m_boid_shader.post_render(  );
      glPopMatrix();
    }
    else
    {
      OpenTissue::gl::ColorPicker(0.7,0.1,.7);
      OpenTissue::gl::DrawPoint(m_boid_position,0.2);
      OpenTissue::gl::ColorPicker(0.1,0.3,.7);
      OpenTissue::gl::DrawVector(m_boid_position,m_boid_normal);
      OpenTissue::gl::ColorPicker(0.1,0.7,.3);
      OpenTissue::gl::DrawVector(m_boid_position, m_boid_dof );
    }

  }
  void render_clouds(int state){
	  if(state>1){
		  glPushMatrix();
		  OpenTissue::gl::Transform(vector3_type(-70,-70,0));
		  m_clouds.update(vector3_type(1.5,2,0),0.5f);
		  m_clouds.render(this->camera().position(),this->camera().dof(),vector3_type(-70,-70,0));
		  glPopMatrix();
	  }
  }
  void render_sun(){
	  //if the moon is under the the horizon don't waste resources trying to render it
	  if(m_sun_dir_wcs(2)<-0.1)return;
      glPushMatrix();
      OpenTissue::gl::Transform(m_boid_position);
	  glDepthMask(GL_FALSE);
	  /*
	    render sun 
	  */
	  m_sun_shader.pre_render(
		  m_reload_shaders,
		  m_camera.right()(0), m_camera.right()(1), m_camera.right()(2),
		  m_camera.up()(0)   , m_camera.up()(1)   , m_camera.up()(2),
		  m_time,
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2]);
	  glBegin(GL_QUADS);
	  glColor3f(1,0,0);
	  glVertex3f(m_sun_dir_wcs(0),m_sun_dir_wcs(1),m_sun_dir_wcs(2)); 
	  glColor3f(1,1,0);
	  glVertex3f(m_sun_dir_wcs(0),m_sun_dir_wcs(1),m_sun_dir_wcs(2)); 	
	  glColor3f(0,1,0);
	  glVertex3f(m_sun_dir_wcs(0),m_sun_dir_wcs(1),m_sun_dir_wcs(2)); 
	  glColor3f(0,0,0);
	  glVertex3f(m_sun_dir_wcs(0),m_sun_dir_wcs(1),m_sun_dir_wcs(2)); 
	  glEnd();
	  m_sun_shader.post_render();
	  glDepthMask(GL_TRUE); 
	  glPopMatrix();
  }

  void render_moon(){
	  //if the moon is under the the horizon don't waste resources trying to render it
	  if(m_moon_dir_wcs(2)<-0.1)return;
      glPushMatrix();
      OpenTissue::gl::Transform(m_boid_position);
	  glDepthMask(GL_FALSE);
	  /*
	  render moon
	  */
	  m_moon_shader.pre_render(
		  m_reload_shaders,
		  m_time,m_day_length,
		  m_camera.right()(0), m_camera.right()(1), m_camera.right()(2),
		  m_camera.up()(0)   , m_camera.up()(1)   , m_camera.up()(2),
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2]);
	  glBegin(GL_QUADS);
	  glColor3f(1,0,0);
	  glVertex3f(m_moon_dir_wcs(0),m_moon_dir_wcs(1),m_moon_dir_wcs(2)); 
	  glColor3f(1,1,0);
	  glVertex3f(m_moon_dir_wcs(0),m_moon_dir_wcs(1),m_moon_dir_wcs(2));  	
	  glColor3f(0,1,0);
	  glVertex3f(m_moon_dir_wcs(0),m_moon_dir_wcs(1),m_moon_dir_wcs(2)); 
	  glColor3f(0,0,0);
	  glVertex3f(m_moon_dir_wcs(0),m_moon_dir_wcs(1),m_moon_dir_wcs(2)); 
	  glEnd();
	  m_moon_shader.post_render();
	  glDepthMask(GL_TRUE);	
	  glPopMatrix();
  }

  void render_sky_dome_clods(bool flipped){
	  if(m_clouds_state==0||m_clouds_state==2)return;

	  glPushMatrix();	  
	  OpenTissue::gl::Transform(m_boid_position);
	  OpenTissue::gl::Transform(vector3_type(0,0,-15));
	  if(!m_sky_cloud_shader.pre_render(
		  m_reload_shaders,
		  m_time,
		  -m_dome_radius,-m_dome_radius,-m_dome_radius,
		  2*m_dome_radius,2*m_dome_radius,2*m_dome_radius,	
		  m_light_dir_view(0),m_light_dir_view(1),m_light_dir_view(2),
		  m_light_intensity,
		  FogDensity(),
		  m_fog_color[0],m_fog_color[1],m_fog_color[2],
		  flipped)
		  ){
		  return;
	  }
	  /*
	    render skydome
	  */
	  glEnable(GL_BLEND);
	  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	  m_sky_dome.vertex_object_render();
	  glDisable(GL_BLEND);
	  glPopMatrix();
	  m_sky_cloud_shader.post_render();
  }


  void render_sky_color(bool shader, bool wireframe,bool flipped){
	  glPushMatrix();
	  OpenTissue::gl::Transform(m_boid_position);
	  OpenTissue::gl::Transform(vector3_type(0,0,-15));
	  if(shader){
		  if(!m_sky_shader.pre_render(
			  m_reload_shaders,
			  m_time,
			  m_day_time/m_day_length,
			  (m_day_length/24.0)/m_day_length,
			  FogDensity(),
			  m_fog_color[0],m_fog_color[1],m_fog_color[2],
			  flipped)
			 ){
			  m_sky_shader_on=false;
			  shader=false;
			  m_sky_shader.post_render();
			  OpenTissue::gl::ColorPicker(0.1,0.5,.7);
		  }
	  }else{
		  OpenTissue::gl::ColorPicker(0.1,0.5,.7);
	  }
	  /*
	  render skydome
	  */
	  if(!wireframe){
		  m_sky_dome.vertex_object_render();
	  }
	  if(shader){
		  m_sky_shader.post_render();
	  }
	  glPopMatrix();
  }

  void render_sky_dome( bool enabled, bool shader, bool wireframe,bool flipped){
	  if(!enabled)
		  return;
	  render_sky_color(shader,wireframe,flipped);
	  if(shader){
		  render_sun();
		  render_moon();
		  render_sky_dome_clods(flipped);
	  }
  }

  void movement_update()
  {
    m_boid_dof = OpenTissue::math::Rz(m_boid_steering_angle)*vector3_type(0.0,1.0,0.0);
    m_boid_position += m_boid_speed*m_boid_dof;
    m_grid_manager.place(m_boid_position,m_cell_generator);
    types::cell_type * cell = &(m_grid_manager.cell(m_grid_manager.s(),m_grid_manager.t()));
    compute_heightmap_point(
      cell->get_geometry(0)
      , m_cell_generator.I()
      , m_cell_generator.J()
      , m_cell_width
      , m_cell_height
      , m_boid_position(0)
      , m_boid_position(1)
      , m_boid_position
      , m_boid_normal
      );

	//Anti submarine code, the boid can not be positioned below water.
	if(m_boid_position(2)<m_water_level){
		m_boid_position(2)=m_water_level;
	}

    m_boid_dof = m_boid_normal % unit(m_boid_dof % m_boid_normal);
    if(m_follow_boid)
    {
      vector3_type p = m_boid_position + (OpenTissue::math::Rz(m_boid_steering_angle)*m_boid_tracking_vector);
      vector3_type up =m_boid_normal;
      vector3_type target = m_boid_position;
      this->camera().init(p,target,up);
    }
  }


  void update_boid_tracking_vector()
  {
    if(m_follow_boid)
    {
      m_boid_tracking_vector = OpenTissue::math::Rz(-m_boid_steering_angle) * (m_camera.position() - m_boid_position);
    }
  }

};

OpenTissue::glut::instance_pointer init_glut_application(int /*argc*/, char ** /*argv*/)
{
  OpenTissue::glut::instance_pointer instance;
  instance.reset( new Application() );
  return instance;
}
